import sys
import asyncio
import traceback
import cv2
import numpy as np

from PyQt5.QtWidgets import QApplication, QMainWindow, QFrame, QLabel
from PyQt5.QtGui import QKeyEvent, QMovie, QPixmap, QImage
from PyQt5.QtCore import Qt, QTimer
from multiprocessing import Process, Queue, Event
import multiprocessing.sharedctypes as mps
from MyLib.TestToolApi import Debug
from ctypes import *
from typing import Optional


class MainVideoProcess(Process):

    def __init__(self, logging=True, daemon=True):
        super(MainVideoProcess, self).__init__(daemon=daemon)
        if logging:
            self.__mainDebugQueue = Queue(10)
        else:
            self.__mainDebugQueue = None
        self.__mainDebug = Debug(self.__mainDebugQueue, True, "下位机-客户端模块-音视频流服务")
        self.__MainVideoPauseStatus = Event()
        self.__CloseStatus = Event()
        self.MAIN_VIDEO_STATUS = mps.Value(c_bool, False)
        self.MAIN_VIDEO_DATA = mps.Array(c_char, size_or_initializer=720 * 1280 * 3)

    async def __getVideoTask(self):
        self.__mainDebug.info("[音视频流获取器] 已进入该任务")
        # self.__MainVideoPauseStatus.set()
        self.MAIN_VIDEO_STATUS.value = False
        while not self.__CloseStatus.is_set():
            try:
                self.__mainDebug.info("[音视频流获取器] 等待任务启动")
                while self.__MainVideoPauseStatus.is_set():
                    if self.__CloseStatus.is_set():
                        break
                    await asyncio.sleep(0)
                if self.__CloseStatus.is_set():
                    break
                else:
                    self.__mainDebug.info("[音视频流获取器] 任务启动成功!")
                    videoStream = await asyncio.subprocess.create_subprocess_shell(
                        "ffmpeg -f flv -i rtmp://139.155.181.21/live/03 -an -f rawvideo -pix_fmt bgr24 -",
                        stdout=asyncio.subprocess.PIPE,
                        stderr=asyncio.subprocess.DEVNULL,
                        shell=True
                    )
                    audioStream = await asyncio.subprocess.create_subprocess_shell(
                        "ffmpeg -f flv -i rtmp://139.155.181.21/live/03 -vn -f wav - | aplay -",
                        stdout=asyncio.subprocess.DEVNULL,
                        stderr=asyncio.subprocess.DEVNULL,
                        shell=True
                    )
                    self.__mainDebug.info("[音视频流获取器] 获取数据中...")
                    while not self.__MainVideoPauseStatus.is_set():
                        if self.__CloseStatus.is_set():
                            break
                        else:
                            print("正在获取")
                            rawData = await videoStream.stdout.readexactly(480 * 640 * 3)
                            self.MAIN_VIDEO_STATUS.value = True
                            # self.MAIN_VIDEO_STATUS = False
                            self.MAIN_VIDEO_DATA.raw = rawData
                            # self.MAIN_VIDEO_STATUS = True
                            # print("写入的", len(rawData))
                    self.__mainDebug.debug("[音视频流获取器] 任务被暂停!")
                    videoStream.terminate()
                    audioStream.terminate()
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("[音视频流获取器] 该任务发生错误, 退出!")
                break
        if self.__CloseStatus.is_set():
            self.__mainDebug.warn("[音视频流获取器] 出现全局错误申请, 退出该任务!")
        self.__CloseStatus.set()
        self.__mainDebug.warn("[音视频流获取器] 任务被中止!")

    def run(self) -> None:
        self.__mainDebug.info("进程启动中...")

        async def main():
            await asyncio.gather(self.__getVideoTask())

        asyncio.run(main())

        self.__mainDebug.info("进程已结束!")

    def play(self):
        self.__MainVideoPauseStatus.clear()

    def pause(self):
        self.__MainVideoPauseStatus.set()

    def stop(self):
        self.__CloseStatus.set()


class WindowInit(QMainWindow):

    def __init__(self):
        super(WindowInit, self).__init__()
        self.MAIN_VIDEO_STATUS: Optional[mps.Value] = None
        self.MAIN_VIDEO_DATA: Optional[mps.Value] = None

        self.AudioVideoProcess = MainVideoProcess()
        self.MAIN_VIDEO_STATUS = self.AudioVideoProcess.MAIN_VIDEO_STATUS
        self.MAIN_VIDEO_DATA = self.AudioVideoProcess.MAIN_VIDEO_DATA
        self.AudioVideoProcess.start()

        self.pointPixmap = QPixmap('icon/wait.jpeg')
        self.centerFrame = QLabel()
        self.centerFrame.setPixmap(self.pointPixmap)
        self.centerFrame.setScaledContents(True)
        self.centerFrame.setFrameShape(QFrame.Box)
        self.centerFrame.setFrameShadow(QFrame.Plain)
        self.centerFrame.setLineWidth(3)
        self.setCentralWidget(self.centerFrame)

        self.freshImageTimer = QTimer()
        self.freshImageTimer.setInterval(33)
        self.freshImageTimer.timeout.connect(self.__freshImage)
        self.freshImageTimer.start()
        self.AudioVideoProcess.play()

    def windowShow(self):
        self.showFullScreen()

    def keyPressEvent(self, a0: QKeyEvent) -> None:
        key = a0.key()
        keyStatus = a0.isAutoRepeat()
        if not keyStatus:
            if key == Qt.Key_Escape:
                self.close()

    def closeEvent(self, a0) -> None:
        self.AudioVideoProcess.pause()
        self.AudioVideoProcess.stop()
        self.AudioVideoProcess.join(1)
        self.AudioVideoProcess.kill()

    def __freshImage(self):
        if self.MAIN_VIDEO_STATUS.value:
            payload = self.MAIN_VIDEO_DATA.raw
            frame = np.frombuffer(payload, np.uint8).reshape((480, 640, 3))
            imageCV2_RGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            # print("成功读取2")
            imageRow, imageCol, imageChannel = imageCV2_RGB.shape
            # print("成功读取3")
            byterPerLine = imageCol * imageChannel
            # print("成功读取4")
            imageQt = QImage(imageCV2_RGB, imageCol, imageRow, byterPerLine, QImage.Format_RGB888)
            # print("成功读取5")
            imageQPixmap = QPixmap.fromImage(imageQt)
            # print("成功读取6")
            self.centerFrame.setPixmap(imageQPixmap)
        else:
            self.centerFrame.setPixmap(self.pointPixmap)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = WindowInit()
    main_window.windowShow()
    sys.exit(app.exec_())
